package paim.wingchun.controller.eventos;


import java.awt.Cursor;
import java.lang.ref.WeakReference;
import java.util.EventObject;
import java.util.List;
import java.util.logging.Level;

import paim.wingchun.app.WC_Log;
import paim.wingchun.controller.AbstractSimpleController;
import paim.wingchun.model.pojos.Erro;
import paim.wingchun.model.pojos.Pojo;
import paim.wingchun.view.AbstractSimpleView;
import paim.wingchun.view.componentes.toolbar.JNavegador;
import paim.wingchun.view.componentes.toolbar.NavegadorListener;

public class DefaultNavegadorEvent implements NavegadorListener {

    WeakReference<AbstractSimpleController<?, ?>> controlador;

    private WeakReference<JNavegador> navegador;

    private ThreadValidacao threadValidacao;

    protected enum Estado {
        OCIOSO, NAVEGANDO
    };

    protected Estado estado = Estado.OCIOSO;

    // /** validacao Otimizada */
    // static boolean otimizacao = true;

    public DefaultNavegadorEvent(AbstractSimpleController<?, ?> controlador) throws Exception {

        this.controlador = new WeakReference<AbstractSimpleController<?, ?>>(controlador);

        JNavegador jNavegador = ((AbstractSimpleView<?>) controlador.getVisao()).getNavegador();
        this.navegador = new WeakReference<JNavegador>(jNavegador);
    }

    @Override
    public void primeiro(EventObject eventObject) {
        navegar(eventObject);
    }

    @Override
    public void anterior(EventObject eventObject) {
        navegar(eventObject);
    }

    @Override
    public void proximo(EventObject eventObject) {
        navegar(eventObject);
    }

    @Override
    public void ultimo(EventObject eventObject) {
        navegar(eventObject);
    }

    @Override
    public void carrega(EventObject eventObject) {
        changeEstado(Estado.NAVEGANDO);

        if ( eventObject != null )
            setObjeto((Long) eventObject.getSource());
        else
            setObjeto(null);

        changeEstado(Estado.OCIOSO);
    }

    @Override
    public boolean podeNavegar() {
        if ( this.controlador.get().getVisao().isEditando() )
            return false;
        return true;
    }

    public Estado getEstado() {
        return estado;
    }

    private void changeEstado(Estado estado) {

        this.estado = estado;
        AbstractSimpleController<?, ?> controlador = this.controlador.get();

        switch ( estado ) {
            case OCIOSO:
                if ( controlador.getVisao().getCursor().getType() != Cursor.DEFAULT_CURSOR )
                    controlador.getVisao().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            break;
            case NAVEGANDO:
                if ( controlador.getVisao().getCursor().getType() != Cursor.WAIT_CURSOR )
                    controlador.getVisao().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            break;
        }
    }

    /** de fato vai para outro registro */
    private void navegar(EventObject eventObject) {
        if ( getEstado() != Estado.OCIOSO )
            return;

        changeEstado(Estado.NAVEGANDO);

        AbstractSimpleController<?, ?> controlador = this.controlador.get();

        Pojo pojo = (Pojo) controlador.getObjeto();

        // /* Busca objeto no navegador */
        // Long registro = (Long) this.navegador.get().getRegistro();

        /* Interrompe a thread de validacao pois nenhum objeto pode estar em uso quando o evict for executado */
        // if ( /* otimizacao && */threadValidacao != null ) {
        interrompeValidacao();
        // }

        // /* simplismente carregar proximo registro */
        // if ( !controlador.getVisao().isEditando() ) {
        // if ( registro == null )
        // this.navegador.get().atualizaUltimoID(pojo.getId());
        // else

        /* apenas garantindo a classe do pojo */
        if ( controlador.getpClass().isAssignableFrom(pojo.getClass()) )
            /* Descarta o objeto do cache para evitar incremento desnecessario de versao. */
            controlador.getSessao().evict(pojo);

        setObjeto((Long) eventObject.getSource());
        // }
        // /* persiste atual antes de navegar */
        // else {
        // /* Descarta o pojo do cache para evitar incremento desnecessario de versao. */
        // if ( id != null && controlador.getpClass().isAssignableFrom(pojo.getClass()) ) {
        // controlador.getSessao().evict(pojo);
        // }
        //
        // setObjeto((Long) eventObject.getSource());
        //
        // /** Habilita botï¿½o fechar */
        // controlador.getVisao().setEditando(false);
        // }

        changeEstado(Estado.OCIOSO);
    }

    /** coloca objeto na visao */
    private void setObjeto(final Long id) {

        AbstractSimpleController<?, ?> controlador = this.controlador.get();
        // JNavegador navegador = this.navegador.get();

        /* Bloqueia o disparo de eventos de mudanï¿½a de conteudo */
        controlador.freeze();
        try {
            if ( id != null ) {
                final Pojo pojo = controlador.getModelo().get(controlador.getSessao(), id);

                /* popula visao com um pojo */
                controlador.setObjeto(pojo);

                interrompeValidacao();
                /* so valida se o pojo estiver com pendencia */
                if ( pojo.getPendencia() > 0 ) {
                    threadValidacao = new ThreadValidacao(pojo);
                    /* dispara nova thread de validacao */
                    threadValidacao.start();
                }
            }
        }
        catch ( Exception e ) {
            WC_Log.getInstancia().getlogger().log(Level.SEVERE, e.getMessage(), e);
        }
        finally {
            /* Permite o disparo de eventos de mudanca de conteudo */
            controlador.warmup();
        }
    }

    /** interrompe, se houver, a thread de validacao */
    private void interrompeValidacao() {
        try {
            if ( threadValidacao != null ) {
                threadValidacao.interrompeValidacao();
                threadValidacao = null;
            }
        }
        catch ( Exception e ) {
            WC_Log.getInstancia().getlogger().log(Level.SEVERE, e.getMessage(), e);
        }
    }

    /** valida por thread o pojo ao navegar */
    protected class ThreadValidacao extends Thread {

        private Pojo pojo;

        public ThreadValidacao(Pojo pojo) {
            super();
            this.pojo = pojo;
        }

        @Override
        public void run() {

            if ( isInterrupted() )
                return;

            if ( !DefaultNavegadorEvent.this.navegador.get().getRegistro().equals(pojo.getId()) )
                return;

            List<Erro> errosValidacao = DefaultNavegadorEvent.this.controlador.get().validar(pojo);
            DefaultNavegadorEvent.this.controlador.get().getVisao().refreshErros(errosValidacao);

            if ( isInterrupted() )
                return;

            Thread.yield();

            if ( isInterrupted() )
                return;

            DefaultNavegadorEvent.this.controlador.get().getVisao().refreshErros(errosValidacao);
        }

        public void interrompeValidacao() {

            try {
                if ( this.isAlive() ) {
                    this.setPriority(Thread.MIN_PRIORITY);
                    this.interrupt();
                }
            }
            catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }

}
